﻿using System;
using System.Collections.Generic;
using System.Text;
using CID.Execution.Agent.Support;
using CID.Execution.Support.Information;
using CID.Execution.Support.Scripting;
using CID.Support;
using NailsFramework;

namespace CID.Execution.Agent
{
    abstract class BaseScriptExecuter<TScript, TScriptStep> : IScriptExecuter 
        where TScript :IScript<TScriptStep> 
        where TScriptStep : ScriptStep
    {
        protected BaseScriptExecuter(TScript script)
        {
            Script = script;
            ControllerServiceProxyFactory = Nails.ObjectFactory.GetObject<IControllerServiceProxyFactory>();
        }

        public TScript Script { get; private set; }

        protected IControllerServiceProxyFactory ControllerServiceProxyFactory { get; private set; }

        public void Execute()
        {
            var detailsBuilder = new StringBuilder();
            var error = false;
            OnExecutionStarted(Script, detailsBuilder);
            try
            {
                foreach (var step in Script.Steps)
                    ExecuteStep(step, detailsBuilder);
            }
            catch (Exception ex)
            {
                AppendMessage(detailsBuilder, "Execution failed due to an unexpected exception");
                AppendMessage(detailsBuilder, "Exception details {0}", ex.ToString());
                error = true;
            }
            OnExecutionEnded(Script, detailsBuilder.ToString(), error);
        }

        protected void AppendMessage(StringBuilder builder, string format, params object[] args)
        {
            builder.AppendFormat("{0:yyyy-MM-dd HH:mm:ss}\t{1}", ApplicationDateTime.Now, String.Format(format, args));
            builder.AppendLine();
        }

        protected IEnumerable<ParameterValueInfo> GetGeneralAdditionalParameterValues()
        {
            var result = new List<ParameterValueInfo>();
            result.Add(ParameterValueInfo.CreateAdditionalParameterValue(ParameterValueInfo.ReservedParameterNames.ReleaseName, Script.Release.Name));
            return result;
        }

        protected void NotifyControllerCommnunicationError(Exception ex)
        {
            String.Format("There was an error while contacting the controller to notify the completion of execution for the {0} of {1}. Error was {2}", Script.GetType().Name, Script.DeploymentUniqueIdentifier, ex);
            //TODO: log the error
        }

        protected abstract void ExecuteStep(TScriptStep step, StringBuilder detailsBuilder);
        
        protected abstract void OnExecutionStarted(TScript script, StringBuilder detailsBuilder);

        protected abstract void OnExecutionEnded(TScript script, string details, bool error);
    }
}
